
#include "Box.h"
#include "BoundingBox.h"
#include "HitRecord.h"
#include "Point.h"
#include "Ray.h"
#include "Vector.h"
#include <math.h>

Box::Box(Material* material, const Point& corner1, const Point& corner2)
  : Primitive(material)
{
  min = Min(corner1, corner2);
  max = Max(corner1, corner2);
  span = Point(max.x() - min.x(), max.y() - min.y(), max.z() - min.z());
}

Box::~Box()
{
}

void Box::getBounds(BoundingBox& bbox) const
{
  bbox.extend(min);
  bbox.extend(max);
}

void Box::intersect(HitRecord& hit, const RenderContext&, const Ray& ray) const
{
  Vector inverse_direction = ray.direction().inverse();
  Vector v1 = (min - ray.origin()) * inverse_direction;
  Vector v2 = (max - ray.origin()) * inverse_direction;
  Vector vmin = Min(v1, v2);
  Vector vmax = Max(v1, v2);
  double near = vmin.maxComponent();
  double far = vmax.minComponent();
  if(near < far && (near > EPSILON || far > EPSILON) && (far < DBL_MAX)) {
	  if(!hit.hit(near, this, matl))
			  hit.hit(far, this, matl);
  }
  return;
}

void Box::normal(Vector& normal, const RenderContext&, const Point& hitpos,
                    const Ray& ray, const HitRecord& hit) const
{
	if (hitpos.x() < min.x() + EPSILON && hitpos.x() > min.x() - EPSILON) { //lower x face
		normal = Vector(-1, 0, 0);
	} else if (hitpos.y() < min.y() + EPSILON && hitpos.y() > min.y() - EPSILON) { //lower y face
		normal = Vector(0, -1, 0);
	} else if (hitpos.z() < min.z() + EPSILON && hitpos.z() > min.z() - EPSILON) { //lower z face
		normal = Vector(0, 0, -1);
	} else if (hitpos.x() < max.x() + EPSILON && hitpos.x() > max.x() - EPSILON) { //higher x face
		normal = Vector(1, 0, 0);
	} else if (hitpos.y() < max.y() + EPSILON && hitpos.y() > max.y() - EPSILON) { //higher y face
		normal = Vector(0, 1, 0);
	} else if (hitpos.z() < max.z() + EPSILON && hitpos.z() > max.z() - EPSILON) { //higher z face
		normal = Vector(0, 0, 1);
	} else {
		normal = Vector(0, 0, 0);
	}

}

void Box::computeUVW(Vector& uvw, const RenderContext& context,
                           const Ray& ray, const HitRecord& hit) const
{
	Point hitpos = ray.origin()+ray.direction()*hit.minT();
	uvw = Vector((hitpos.x() - min.x()) / span.x(),
			(hitpos.y() - min.y()) / span.y(),
			(hitpos.z() - min.z()) / span.z());
}

